package com.smmisia.article.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smmisia.article.entity.Point;
import com.smmisia.article.entity.PointStream;
import com.smmisia.article.enums.SignChangeType;
import com.smmisia.article.enums.SignSource;
import com.smmisia.article.mapper.PointMapper;
import com.smmisia.article.mapper.PointStreamMapper;
import com.smmisia.article.response.SignResponse;
import com.smmisia.article.service.PointService;
import com.smmisia.article.utils.LotterySystem;
import com.smmisia.common.Result.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/point")
@Slf4j
@Tag(name = "积分管理")
public class PointController {

    @Autowired
    private PointService pointService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private PointMapper pointMapper;

    @Autowired
    private PointStreamMapper pointStreamMapper;

    private static final String USER_POINTS_KEY = "user:points:";
    private static final String USER_TARGET_KEY = "user:target:";
    private static final String USER_DRAW_COUNT = "user:draw:count:";
    private static final String USER_POINTS_COUNT = "user:points:count:";
    private static final String USER_DRAW_HISTORY = "user:draw:history:";

    private final LotterySystem lotterySystem;

    public PointController() {
        this.lotterySystem = new LotterySystem();
        // 初始化奖池
        initPrizePool();
    }

    private void initPrizePool() {
        lotterySystem.addToPrizePool(new LotterySystem.Prize(1L, "iPhone 15", LotterySystem.PrizeType.PHYSICAL, 5999,LocalDateTime.now()));
        lotterySystem.addToPrizePool(new LotterySystem.Prize(2L, "iPad Pro", LotterySystem.PrizeType.PHYSICAL, 6999,LocalDateTime.now()));
        lotterySystem.addToPrizePool(new LotterySystem.Prize(3L, "AirPods", LotterySystem.PrizeType.PHYSICAL, 1299,LocalDateTime.now()));
    }
    /**
     * 用户签到,增加积分
     *
     * @return
     */
    @GetMapping("/sign")
    @Operation(summary = "用户签到")
    public Result<String> sign() {
        return pointService.sign();
    }

    /**
     * 用户连续签到天数
     *
     * @return
     */
    @GetMapping("/signTotal")
    @Operation(summary = "用户连续签到天数")
    public Result<String> signTotal() {
        return pointService.signTotal();
    }

    @GetMapping("/getSign")
    public Result<SignResponse> getSign() {
        return pointService.getSign();
    }

    @GetMapping("/getTarget")
    @Operation(summary = "获取定轨物品")
    public Result getTargetAll() {
        int userId = StpUtil.getLoginIdAsInt();
        LotterySystem.Prize prize = (LotterySystem.Prize) redisTemplate.opsForValue().get(USER_TARGET_KEY + userId);
        if (prize == null) {
            return Result.ok("未设置定轨");
        }
        return Result.ok(prize);
    }

    @GetMapping("/getTargetAll")
    @Operation(summary = "获取所有定轨物品")
    public Result getTarget() {
        List<LotterySystem.Prize> prizePool = lotterySystem.getPrizePool();
        if (prizePool == null) {
            return Result.ok("未设置定轨");
        }
        return Result.ok(prizePool);
    }

    @PostMapping("/setTarget")
    @Operation(summary = "设置定轨物品")
    public Result setTarget(@RequestParam Long prizeId) {
        int userId = StpUtil.getLoginIdAsInt();
        String lockKey = "lock:target:" + userId;
        try {
            Boolean locked = stringRedisTemplate.opsForValue()
                    .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(locked)) {
                return Result.fail("操作太频繁");
            }

            LotterySystem.Prize prize = lotterySystem.getPrizePool().stream()
                    .filter(p -> p.getId().equals(prizeId))
                    .findFirst()
                    .orElse(null);

            if (prize == null) {
                return Result.fail("奖品不存在");
            }

            lotterySystem.setTargetPrize(prize);
            redisTemplate.opsForValue().set(USER_TARGET_KEY + userId, prize);

            return Result.ok("设置定轨成功");
        } catch (Exception e) {
            log.error("设置定轨失败", e);
            return Result.fail("设置失败");
        } finally {
            stringRedisTemplate.delete(lockKey);
        }
    }

    @PostMapping("/draw")
    @Operation(summary = "抽奖")
    public Result draw(@RequestParam Integer drawTimes) {
        int userId = StpUtil.getLoginIdAsInt();
        String lockKey = "lock:lottery:" + userId;

        try {
            Boolean locked = stringRedisTemplate.opsForValue()
                    .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(locked)) {
                return Result.fail("操作太频繁");
            }

            if (drawTimes != 1 && drawTimes != 10) {
                return Result.fail("抽奖次数只能是1或10");
            }

            // 检查积分
            //Integer points = (Integer) redisTemplate.opsForValue().get(USER_POINTS_KEY + userId);
            Point point = pointMapper.selectOne(Wrappers.lambdaQuery(Point.class).eq(Point::getUserId, userId));
            Integer points = point.getPoint();
            if (points == null || points < 100 * drawTimes) {
                return Result.fail("积分不足");
            }

            // 获取历史数据
            Integer prizeCount = (Integer) redisTemplate.opsForValue().get(USER_DRAW_COUNT + userId);
            Integer pointsCount = (Integer) redisTemplate.opsForValue().get(USER_POINTS_COUNT + userId);
            if (prizeCount == null) prizeCount = 0;
            if (pointsCount == null) pointsCount = 0;

            // 设置抽奖系统状态
            lotterySystem.setPrizeDrawCount(prizeCount);
            lotterySystem.setPointsDrawCount(pointsCount);

            List<LotterySystem.Prize> results = new ArrayList<>();
            for (int i = 0; i < drawTimes; i++) {
                LotterySystem.Prize result = lotterySystem.draw();
                results.add(result);
                redisTemplate.opsForList().rightPush(USER_DRAW_HISTORY + userId, result);
            }

            // 扣除积分并更新计数
            //redisTemplate.opsForValue().set(USER_POINTS_KEY + userId, points - 100 * drawTimes);
            pointMapper.update(new Point(), Wrappers.lambdaUpdate(Point.class)
                    .eq(Point::getUserId, userId)
                    .setSql("point = point - " + 100 * drawTimes));
            PointStream pointStream = new PointStream();
            pointStream.setUserId(userId);
            pointStream.setChangeType(SignChangeType.SIGN_OUT);
            pointStream.setChangeCount(100 * drawTimes);
            pointStream.setSource(SignSource.PRIZE);
            pointStream.setCreateTime(LocalDateTime.now());
            pointStreamMapper.insert(pointStream);
            redisTemplate.opsForValue().set(USER_DRAW_COUNT + userId, lotterySystem.getPrizeDrawCount());
            redisTemplate.opsForValue().set(USER_POINTS_COUNT + userId, lotterySystem.getPointsDrawCount());

            return Result.ok(results);
        } catch (Exception e) {
            log.error("抽奖失败", e);
            return Result.fail("抽奖失败");
        } finally {
            stringRedisTemplate.delete(lockKey);
        }
    }

    /**
     * 获取抽奖记录
     */
    @GetMapping("/getDrawHistory")
    @Operation(summary = "获取抽奖记录")
    public Result getDrawHistory() {
        int userId = StpUtil.getLoginIdAsInt();
        List<Object> objectList = redisTemplate.opsForList().range(USER_DRAW_HISTORY + userId, 0, -1);
        List<LotterySystem.Prize> history = (List<LotterySystem.Prize>) (List<?>) objectList;
        return Result.ok(history);
    }
}